﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;

namespace LevelEditor.View.Controls.Adorners
{
    public class ResizeAdorner : Adorner
    {
        // Fields
        private Rect bottomLeftSquare;
        private Rect bottomRightSquare;
        private Rect bottomSquare;
        private ResizeMoveDirection direction;
        private Rect leftSquare;
        private Point offset;
        private Rect rect;
        private SolidColorBrush renderBrush;
        private Pen renderPen;
        private Rect rightSquare;
        private FrameworkElement scene;
        public int SQUARE_SIZE;
        private Rect topLeftSquare;
        private Rect topRightSquare;
        private Rect topSquare;
        private FrameworkElement workArea;

        // Methods
        public ResizeAdorner(UIElement adornedElement, FrameworkElement scene)
            : base(adornedElement)
        {
            this.SQUARE_SIZE = 5;
            this.InitComponent(adornedElement, scene, null);
        }

        public ResizeAdorner(UIElement adornedElement, FrameworkElement scene, FrameworkElement workArea)
            : base(adornedElement)
        {
            this.SQUARE_SIZE = 5;
            this.InitComponent(adornedElement, scene, workArea);
        }

        private void InitComponent(UIElement adornedElement, FrameworkElement scene, FrameworkElement workArea)
        {
            base.MouseDown += new MouseButtonEventHandler(this.ResizeAdorner_MouseDown);
            base.MouseMove += new MouseEventHandler(this.ResizeAdorner_MouseMove);
            base.MouseUp += new MouseButtonEventHandler(this.ResizeAdorner_MouseUp);
            this.scene = scene;
            this.workArea = workArea;
            if (workArea != null)
            {
                workArea.MouseMove += new MouseEventHandler(this.parent_MouseMove);
                workArea.MouseUp += new MouseButtonEventHandler(this.parent_MouseUp);
            }
            else
            {
                scene.MouseMove += new MouseEventHandler(this.parent_MouseMove);
                scene.MouseUp += new MouseButtonEventHandler(this.parent_MouseUp);
            }
            this.offset = Mouse.GetPosition(base.AdornedElement);
            this.direction = ResizeMoveDirection.None;
            base.IsHitTestVisible = false;
        }

        protected override void OnRender(DrawingContext drawingContext)
        {
            this.rect = new Rect(base.AdornedElement.DesiredSize);
            this.topLeftSquare = new Rect(this.rect.TopLeft.X - (this.SQUARE_SIZE / 2), this.rect.TopLeft.Y - (this.SQUARE_SIZE / 2), (double)this.SQUARE_SIZE, (double)this.SQUARE_SIZE);
            this.topRightSquare = new Rect(this.rect.TopRight.X - (this.SQUARE_SIZE / 2), this.rect.TopRight.Y - (this.SQUARE_SIZE / 2), (double)this.SQUARE_SIZE, (double)this.SQUARE_SIZE);
            this.bottomLeftSquare = new Rect(this.rect.BottomLeft.X - (this.SQUARE_SIZE / 2), this.rect.BottomLeft.Y - (this.SQUARE_SIZE / 2), (double)this.SQUARE_SIZE, (double)this.SQUARE_SIZE);
            this.bottomRightSquare = new Rect(this.rect.BottomRight.X - (this.SQUARE_SIZE / 2), this.rect.BottomRight.Y - (this.SQUARE_SIZE / 2), (double)this.SQUARE_SIZE, (double)this.SQUARE_SIZE);
            this.topSquare = new Rect((this.rect.Width / 2.0) - (this.SQUARE_SIZE / 2), this.rect.TopLeft.Y - (this.SQUARE_SIZE / 2), (double)this.SQUARE_SIZE, (double)this.SQUARE_SIZE);
            this.leftSquare = new Rect(this.rect.TopLeft.X - (this.SQUARE_SIZE / 2), (this.rect.Height / 2.0) - (this.SQUARE_SIZE / 2), (double)this.SQUARE_SIZE, (double)this.SQUARE_SIZE);
            this.rightSquare = new Rect(this.rect.BottomRight.X - (this.SQUARE_SIZE / 2), (this.rect.Height / 2.0) - (this.SQUARE_SIZE / 2), (double)this.SQUARE_SIZE, (double)this.SQUARE_SIZE);
            this.bottomSquare = new Rect((this.rect.Width / 2.0) - (this.SQUARE_SIZE / 2), this.rect.BottomRight.Y - (this.SQUARE_SIZE / 2), (double)this.SQUARE_SIZE, (double)this.SQUARE_SIZE);
            if (this.renderBrush == null)
            {
                this.renderBrush = new SolidColorBrush(DisabledFunctionality ? Colors.Transparent : Colors.Red);
                this.renderBrush.Opacity = 0.2;
                this.renderBrush.Freeze();
            }
            if (this.renderPen == null)
            {
                this.renderPen = new Pen(new SolidColorBrush(DisabledFunctionality ? Colors.Red : Colors.Red), 0.5);
                this.renderPen.Freeze();
            }
            drawingContext.DrawRectangle(this.renderBrush, this.renderPen, this.rect);

            if (DisabledFunctionality) return;

            drawingContext.DrawRectangle(this.renderBrush, this.renderPen, this.topLeftSquare);
            drawingContext.DrawRectangle(this.renderBrush, this.renderPen, this.topRightSquare);
            drawingContext.DrawRectangle(this.renderBrush, this.renderPen, this.bottomLeftSquare);
            drawingContext.DrawRectangle(this.renderBrush, this.renderPen, this.bottomRightSquare);
            drawingContext.DrawRectangle(this.renderBrush, this.renderPen, this.topSquare);
            drawingContext.DrawRectangle(this.renderBrush, this.renderPen, this.leftSquare);
            drawingContext.DrawRectangle(this.renderBrush, this.renderPen, this.rightSquare);
            drawingContext.DrawRectangle(this.renderBrush, this.renderPen, this.bottomSquare);
        }

        protected void parent_MouseMove(object sender, MouseEventArgs e)
        {
            if (DisabledFunctionality) return;

            switch (this.direction)
            {
                case ResizeMoveDirection.NW:
                    e.MouseDevice.SetCursor(Cursors.SizeNWSE);
                    if (e.MouseDevice.LeftButton == MouseButtonState.Pressed)
                    {
                        double height = ((FrameworkElement)base.AdornedElement).Height;
                        double width = ((FrameworkElement)base.AdornedElement).Width;
                        double x = (double)base.AdornedElement.GetValue(Canvas.LeftProperty);
                        double y = (double)base.AdornedElement.GetValue(Canvas.TopProperty);
                        Point canvasPos = e.GetPosition(this.scene);
                        double offsetY = canvasPos.Y - y;
                        double offsetX = canvasPos.X - x;
                        base.AdornedElement.SetValue(Canvas.TopProperty, Math.Min(canvasPos.Y, y + height));
                        base.AdornedElement.SetValue(FrameworkElement.HeightProperty, Math.Max((double)0.0, (double)(height - offsetY)));
                        base.AdornedElement.SetValue(Canvas.LeftProperty, Math.Min(canvasPos.X, x + width));
                        base.AdornedElement.SetValue(FrameworkElement.WidthProperty, Math.Max((double)0.0, (double)(width - offsetX)));
                        IsTransforming = true;
                        return;
                    }
                    IsTransforming = false;
                    return;

                case ResizeMoveDirection.N:
                    e.MouseDevice.SetCursor(Cursors.SizeNS);
                    if (e.MouseDevice.LeftButton == MouseButtonState.Pressed)
                    {
                        double height = ((FrameworkElement)base.AdornedElement).Height;
                        double y = (double)base.AdornedElement.GetValue(Canvas.TopProperty);
                        Point canvasPos = e.GetPosition(this.scene);
                        double offsetY = canvasPos.Y - y;
                        base.AdornedElement.SetValue(Canvas.TopProperty, Math.Min(canvasPos.Y, y + height));
                        base.AdornedElement.SetValue(FrameworkElement.HeightProperty, Math.Max((double)0.0, (double)(height - offsetY)));
                        IsTransforming = true;
                        return;
                    }
                    IsTransforming = false;
                    return;

                case ResizeMoveDirection.NE:
                    e.MouseDevice.SetCursor(Cursors.SizeNESW);
                    if (e.MouseDevice.LeftButton == MouseButtonState.Pressed)
                    {
                        double height = ((FrameworkElement)base.AdornedElement).Height;
                        double x = (double)base.AdornedElement.GetValue(Canvas.LeftProperty);
                        double y = (double)base.AdornedElement.GetValue(Canvas.TopProperty);
                        Point canvasPos = e.GetPosition(this.scene);
                        double offsetY = canvasPos.Y - y;
                        base.AdornedElement.SetValue(Canvas.TopProperty, Math.Min(canvasPos.Y, y + height));
                        base.AdornedElement.SetValue(FrameworkElement.HeightProperty, Math.Max((double)0.0, (double)(height - offsetY)));
                        base.AdornedElement.SetValue(FrameworkElement.WidthProperty, Math.Max((double)0.0, (double)(canvasPos.X - x)));
                        IsTransforming = true;
                        return;
                    }
                    IsTransforming = false;
                    return;

                case ResizeMoveDirection.W:
                    e.MouseDevice.SetCursor(Cursors.SizeWE);
                    if (e.MouseDevice.LeftButton == MouseButtonState.Pressed)
                    {
                        double width = ((FrameworkElement)base.AdornedElement).Width;
                        double x = (double)base.AdornedElement.GetValue(Canvas.LeftProperty);
                        Point canvasPos = e.GetPosition(this.scene);
                        double offsetX = canvasPos.X - x;
                        base.AdornedElement.SetValue(Canvas.LeftProperty, Math.Min(canvasPos.X, x + width));
                        base.AdornedElement.SetValue(FrameworkElement.WidthProperty, Math.Max((double)0.0, (double)(width - offsetX)));
                        IsTransforming = true;
                        return;
                    }
                    IsTransforming = false;
                    return;

                case ResizeMoveDirection.E:
                    e.MouseDevice.SetCursor(Cursors.SizeWE);
                    if (e.MouseDevice.LeftButton == MouseButtonState.Pressed)
                    {
                        double x = (double)base.AdornedElement.GetValue(Canvas.LeftProperty);
                        Point canvasPos = e.GetPosition(this.scene);
                        base.AdornedElement.SetValue(FrameworkElement.WidthProperty, Math.Max((double)0.0, (double)(canvasPos.X - x)));
                        IsTransforming = true;
                        return;
                    }
                    IsTransforming = false;
                    return;

                case ResizeMoveDirection.SW:
                    e.MouseDevice.SetCursor(Cursors.SizeNESW);
                    if (e.MouseDevice.LeftButton == MouseButtonState.Pressed)
                    {
                        double num1 = ((FrameworkElement)base.AdornedElement).Height;
                        double width = ((FrameworkElement)base.AdornedElement).Width;
                        double x = (double)base.AdornedElement.GetValue(Canvas.LeftProperty);
                        double y = (double)base.AdornedElement.GetValue(Canvas.TopProperty);
                        Point canvasPos = e.GetPosition(this.scene);
                        double num2 = canvasPos.Y;
                        double offsetX = canvasPos.X - x;
                        base.AdornedElement.SetValue(Canvas.LeftProperty, Math.Min(canvasPos.X, x + width));
                        base.AdornedElement.SetValue(FrameworkElement.WidthProperty, Math.Max((double)0.0, (double)(width - offsetX)));
                        base.AdornedElement.SetValue(FrameworkElement.HeightProperty, Math.Max((double)0.0, (double)(canvasPos.Y - y)));
                        IsTransforming = true;
                        return;
                    }
                    IsTransforming = false;
                    return;

                case ResizeMoveDirection.S:
                    e.MouseDevice.SetCursor(Cursors.SizeNS);
                    if (e.MouseDevice.LeftButton == MouseButtonState.Pressed)
                    {
                        double y = (double)base.AdornedElement.GetValue(Canvas.TopProperty);
                        Point canvasPos = e.GetPosition(this.scene);
                        base.AdornedElement.SetValue(FrameworkElement.HeightProperty, Math.Max((double)0.0, (double)(canvasPos.Y - y)));
                        IsTransforming = true;
                        return;
                    }
                    IsTransforming = false;
                    return;

                case ResizeMoveDirection.SE:
                    e.MouseDevice.SetCursor(Cursors.SizeNWSE);
                    if (e.MouseDevice.LeftButton == MouseButtonState.Pressed)
                    {
                        double y = (double)base.AdornedElement.GetValue(Canvas.TopProperty);
                        double x = (double)base.AdornedElement.GetValue(Canvas.LeftProperty);
                        Point canvasPos = e.GetPosition(this.scene);
                        base.AdornedElement.SetValue(FrameworkElement.WidthProperty, Math.Max((double)0.0, (double)(canvasPos.X - x)));
                        base.AdornedElement.SetValue(FrameworkElement.HeightProperty, Math.Max((double)0.0, (double)(canvasPos.Y - y)));
                        IsTransforming = true;
                        return;
                    }
                    IsTransforming = false;
                    return;

                case ResizeMoveDirection.ALL:
                    e.MouseDevice.SetCursor(Cursors.SizeAll);
                    if (e.MouseDevice.LeftButton == MouseButtonState.Pressed)
                    {
                        Point canvasPos = e.GetPosition(this.scene);

                        canvasPos.Offset(-this.offset.X, -this.offset.Y);
                        if (this.SnapToGrid)
                        {
                            double offsetX = canvasPos.X % ((double)this.GridSquareSize);
                            double offsetY = canvasPos.Y % ((double)this.GridSquareSize);
                            double absX = canvasPos.X - offsetX;
                            double absY = canvasPos.Y - offsetY;
                            absX += (offsetX > (this.GridSquareSize / 2)) ? ((double)this.GridSquareSize) : ((double)0);
                            absY += (offsetY > (this.GridSquareSize / 2)) ? ((double)this.GridSquareSize) : ((double)0);
                            canvasPos.X = absX;
                            canvasPos.Y = absY;
                        }
                        base.AdornedElement.SetValue(Canvas.LeftProperty, canvasPos.X);
                        base.AdornedElement.SetValue(Canvas.TopProperty, canvasPos.Y);
                        IsTransforming = true;
                        return;
                    }
                    IsTransforming = false;
                    return;
            }
            /*IsTransforming = false;
            e.MouseDevice.SetCursor(Cursors.Arrow);
            this.direction = ResizeMoveDirection.None;*/
        }

        protected void parent_MouseUp(object sender, MouseButtonEventArgs e)
        {
            if (DisabledFunctionality) return;

            base.IsHitTestVisible = true;
            e.MouseDevice.SetCursor(Cursors.Arrow);
            this.direction = ResizeMoveDirection.None;
        }

        protected void ResizeAdorner_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (DisabledFunctionality) return;

            this.offset = e.GetPosition(base.AdornedElement);
            base.IsHitTestVisible = false;
            Point mousePos = e.GetPosition(base.AdornedElement);
            if (this.topLeftSquare.Contains(mousePos))
            {
                this.direction = ResizeMoveDirection.NW;
            }
            else if (this.topRightSquare.Contains(mousePos))
            {
                this.direction = ResizeMoveDirection.NE;
            }
            else if (this.bottomLeftSquare.Contains(mousePos))
            {
                this.direction = ResizeMoveDirection.SW;
            }
            else if (this.bottomRightSquare.Contains(mousePos))
            {
                this.direction = ResizeMoveDirection.SE;
            }
            else if (this.topSquare.Contains(mousePos))
            {
                this.direction = ResizeMoveDirection.N;
            }
            else if (this.leftSquare.Contains(mousePos))
            {
                this.direction = ResizeMoveDirection.W;
            }
            else if (this.rightSquare.Contains(mousePos))
            {
                this.direction = ResizeMoveDirection.E;
            }
            else if (this.bottomSquare.Contains(mousePos))
            {
                this.direction = ResizeMoveDirection.S;
            }
            else if (this.rect.Contains(mousePos))
            {
                this.direction = ResizeMoveDirection.ALL;
            }
            else
            {
                this.direction = ResizeMoveDirection.None;
                base.IsHitTestVisible = true;
            }
        }

        protected void ResizeAdorner_MouseMove(object sender, MouseEventArgs e)
        {
            if (DisabledFunctionality) return;

            Point mousePos = e.GetPosition(base.AdornedElement);
            if (this.topLeftSquare.Contains(mousePos))
            {
                e.MouseDevice.SetCursor(Cursors.SizeNWSE);
            }
            else if (this.topRightSquare.Contains(mousePos))
            {
                e.MouseDevice.SetCursor(Cursors.SizeNESW);
            }
            else if (this.bottomLeftSquare.Contains(mousePos))
            {
                e.MouseDevice.SetCursor(Cursors.SizeNESW);
            }
            else if (this.bottomRightSquare.Contains(mousePos))
            {
                e.MouseDevice.SetCursor(Cursors.SizeNWSE);
            }
            else if (this.topSquare.Contains(mousePos))
            {
                e.MouseDevice.SetCursor(Cursors.SizeNS);
            }
            else if (this.leftSquare.Contains(mousePos))
            {
                e.MouseDevice.SetCursor(Cursors.SizeWE);
            }
            else if (this.rightSquare.Contains(mousePos))
            {
                e.MouseDevice.SetCursor(Cursors.SizeWE);
            }
            else if (this.bottomSquare.Contains(mousePos))
            {
                e.MouseDevice.SetCursor(Cursors.SizeNS);
            }
            else if (this.rect.Contains(mousePos))
            {
                e.MouseDevice.SetCursor(Cursors.SizeAll);
            }
            else
            {
                e.MouseDevice.SetCursor(Cursors.Arrow);
                this.direction = ResizeMoveDirection.None;
            }
        }

        protected void ResizeAdorner_MouseUp(object sender, MouseButtonEventArgs e)
        {
            if (DisabledFunctionality) return;

            base.IsHitTestVisible = true;
            e.MouseDevice.SetCursor(Cursors.Arrow);
            this.direction = ResizeMoveDirection.None;
        }

        // Properties
        public int GridSquareSize { get; set; }

        public bool SnapToGrid { get; set; }

        public bool DisabledFunctionality { get; set; }

        public bool IsTransforming { get; set; }
    }


}
